home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
ELECTRON
/
0989.ZIP
/
ESPRESSO.ARC
/
MEMORY.C
< prev
next >
Wrap
Text File
|
1987-03-13
|
4KB
|
113 lines
/*
module: memory.c
purpose: Efficient memory management scheme for large blocks of memory
*/
#include "espresso.h"
#ifdef UNIX
#define malloc(n) sbrk((int)n)
#endif
char *malloc();
#define BINS 64
union memory_block {
union memory_block *nextblock; /* Pointer to next block on chain */
int binnum; /* remember bin number */
} *binptr[BINS];
static int num_alloc[BINS], num_active[BINS], alloc_size;
/* mem_stats -- report memory usage statistics */
void mem_stats()
{
register int i, size, active_bytes = 0, alloc_bytes = 0;
for(i = BINS-1; i >= 0; i--) {
size = (i % 2 == 0 ? 3 : 4) << (i/2 - 2);
alloc_bytes += num_alloc[i] * size;
active_bytes += num_active[i] * size;
}
active_bytes = (int) (active_bytes / 1024.0 + 0.5);
alloc_bytes = (int) (alloc_bytes / 1024.0 + 0.5);
printf("# %dK bytes active out of %dK bytes allocated\n",
active_bytes, alloc_bytes);
}
/*
mem_alloc -- allocate an array of "num" objects each of size "size". Also
return the actual number of array elements allocated
*/
char *mem_alloc(num, size, actual)
int num, size, *actual;
{
char *p = alloc(num*size);
*actual = (int) (alloc_size - sizeof(union memory_block)) / size;
return p;
}
/* alloc -- efficiently allocate a (large) array of elements */
char *alloc(bytes)
int bytes;
{
register int log, index, n, request=bytes+sizeof(union memory_block *);
register union memory_block *p;
if( bytes < 0 ) {
printf("Espresso unable to allocate adequate memory in DOS or XENIX\n");
printf("Exiting to OS\n");
exit(-1);
}
/* compute log such that 2**log >= request */
for(n = request-1, log = 1; (n >>= 1) > 0; log++)
;
log -= 2;
/* determine the bin number and actual alloc size (based on the log) */
if (request <= (3 << log))
index = log*2, alloc_size = 3 << log;
else
index = log*2 + 1, alloc_size = 4 << log;
/* See if we have a free block in the garbage list for this bin */
if ((p = binptr[index]) == NULL) {
/* Must allocate a new block -- no free space in garbage list */
p = (union memory_block *) malloc((unsigned) alloc_size);
if (p == NULL) {
/* Check if a larger and free block exists */
for(n = index+1, index = 0; n < BINS; n++)
if (binptr[n] != NULL) {
index=n; p=binptr[index]; binptr[index]=p->nextblock;
break;
}
if (index == 0) {
fprintf(stderr, "espresso: failed allocating %d (%d) bytes\n",
request, alloc_size);
exit(-1);
}
}
num_alloc[index]++;
} else
/* We can reuse the first entry on the garbage list for this size */
binptr[index] = p->nextblock;
num_active[index]++;
p->binnum = index | 0x5500;
return( (char *) (p+1) );
}
/* mem_free -- free the memory allocated */
void mem_free(block)
char *block;
{
register union memory_block *p = (union memory_block *) block - 1;
register int index = p->binnum;
if (((index & 0xFF00) != 0x5500) || ((index &= 0x00FF) >= BINS)) {
fprintf(stderr, "%s: corrupt pointer returned, addr=%x, index=%x\n",
"memory.c/mem_free", p, index);
exit(-1);
}
/* Link p into the garbage list for this block size */
p->nextblock = binptr[index];
binptr[index] = p;
num_active[index]--;
}